const { program } = require('commander');
const fetch = require('node-fetch');
const dataUtil = require('../utils/data');
const fs = require('fs');
const path = require('path')
const UnisatAPI = require('../api/unisat-api')
const unisatApi = new UnisatAPI();
const retry = require('bluebird-retry');

const MempoolAPI = require('../api/mempool')
const mempoolapi = new MempoolAPI();

// pizza总供应量
const supply = 21000000
// unisat用于发送pizza空投的地址
const airdropAddress = 'bc1q0wf9hvqdhwaa2vu3e639sglcu87d06gg4x0mg6';
// pizza空投地址，本地缓存默认文件名
const aidropAddressFileName = 'pizza-airdrop-address.json';
// pizza空投未动地址，本地缓存文件名
const aidropAddressFrozenFileName = 'pizza-airdrop-frozen-address.json';

program
    .option('-f,--filename [filename]', 'Accounts json filename')
    .option('-la,--loadAirdropAddress [loadAirdropAddress]', 'load airdrop address')
    .option('-sa,--sumAirdropAddress [sumAirdropAddress]', 'sum airdrop address')
    .option('-sf,--sumFrozenAddress [sumFrozenAddress]', 'sum frozen address')
    .option('-cftxa,--checkFrozenAddressTxsMinAmount [checkFrozenAddressTxsMinAmount]', 10)
    .option('-cftx,--checkFrozenAddressTxs [checkFrozenAddressTxs]', 'checkFrozenAddressTxs')
    .option('-ic,--isCache [isCache]', 'is cache')
    .option('-cf,--cacheFilename [cacheFilename]', 'cache filename')
    .parse();

let opts = program.opts();
let filename = opts.filename;
let cacheFilename = opts.cacheFilename;
let loadAirdropAddress = opts.loadAirdropAddress || false;
let sumAirdropAddress = opts.sumAirdropAddress || false;
let sumFrozenAddress = opts.sumFrozenAddress || false;
let checkFrozenAddressTxsMinAmount = opts.checkFrozenAddressTxsMinAmount
let checkFrozenAddressTxs = opts.checkFrozenAddressTxs || false;
let isCache = opts.isCache || false;

/// 检查本地缓存文件夹，如不存在创建
let dataDirPath = path.join(process.cwd(), 'data')
if (!fs.existsSync(dataDirPath)) {
    fs.mkdirSync(dataDirPath, { recursive: true });
}


// 重试函数
async function getAddressTxsWithRetry(address) {
    const options = {
        interval: 300,
        max_tries: 3
    };

    const fetchTxs = async () => {
        await _sleep(200)
        return await mempoolapi.getAddressTxs(address);
    };

    return retry(fetchTxs, options);
}

async function run() {
    try {
        // 下载pizza空投地址
        if (loadAirdropAddress) {
            loadPizzaAirdopAddress(filename || aidropAddressFileName);
        }

        // 统计各挡空投数量
        if (sumAirdropAddress) {
            sumPizzaAirdop(filename || aidropAddressFileName);
        }

        // 统计至今未移动过pizza空投的地址信息
        if (sumFrozenAddress) {
            sumPizzaFrozenAddress(filename || aidropAddressFileName, isCache, cacheFilename || aidropAddressFrozenFileName);
        }

        if (checkFrozenAddressTxs) {
            checkFrozenAddressMinTxs();
        }
    } catch (e) {
        console.log(e);
    }
}

function checkFrozenAddressMinTxs() {
    (async () => {
        let filepath = filename || aidropAddressFrozenFileName;
        let dataDirPath = path.join(process.cwd(), '/data/' + filepath);
        if (!fs.existsSync(dataDirPath)) {
            fs.mkdirSync(dataDirPath, { recursive: true });
        }
        let data = dataUtil.readAccountsFromFileSync(dataDirPath);
        let minArray = [];

        try {
            const jsonObject = data;
            const array = Object.entries(jsonObject).map(([key, value]) => ({ address: key, amount: value }));

            const batchSize = 30; // 每批处理的请求数量

            // 递归处理每批次的请求
            const processBatch = async (startIndex) => {
                if (startIndex >= array.length) {
                    // 所有批次处理完毕
                    console.log(`PIZZA交易数量小于等于${checkFrozenAddressTxsMinAmount}的帐号有${minArray.length}个`);
                    let dataDirPath = path.join(process.cwd(), '/data/' + "pizza_mint_txs_"+batchSize+".json");
                    dataUtil.writeAccountsToFileSync(dataDirPath,minArray)
                    return;
                }
                // 取出当前批次的地址
                const batch = array.slice(startIndex, startIndex + batchSize);

                // 为当前批次的每个地址创建请求
                const promises = batch.map(async (element) => {
                    let address = element["address"];
                    try {
                        let txs = await getAddressTxsWithRetry(address);
                        if (txs.length <= checkFrozenAddressTxsMinAmount) {
                            minArray.push(element);
                        }
                        console.log(`address = ${address}, txs = ${txs.length}`);
                    } catch (error) {
                        console.error(`Error fetching transactions for address ${address}:`, error.message);
                    }
                });

                // 等待当前批次的所有请求完成
                await Promise.all(promises);
                await _sleep(100);

                await processBatch(startIndex + batchSize);
            };

            // 开始处理第一个批次
            await processBatch(0);

        } catch (parseError) {
            console.error('Error parsing JSON:', parseError);
        }
    })();
}

/// unisat官方统计空投文档：
/// https://docs.google.com/spreadsheets/d/1fR2DXvDODnjlwwr5X6qEKVWgluIdgp0_zrG4hrnkkQo/edit?gid=1986748241#gid=1986748241
/// 可以对比这份数据来验证代码
async function loadPizzaAirdopAddress(filename) {
    console.log(`开始下载pizza空投地址 ........`);
    let total = await unisatApi.getAddressBrc20HistoryCount({ address: airdropAddress, ticker: 'pizza', type: 'send' });
    console.log(`共计${total}条交易`);
    console.log(`====================`);
    let limit = 10000;
    let page = Math.ceil(total / limit);
    let data = [];
    let dataDir = {};
    let count = 0;
    let dataStr = '';
    for (let i = 0; i < page; i++) {
        let start = i * limit;
        let end = Math.min(start + limit, total);
        console.log(`开始筛选${start}-${end}交易.....`);
        let res = await unisatApi.getAddressBrc20History({ address: airdropAddress, ticker: 'pizza', type: 'send', start: start, limit: limit });
        for (let j = 0; j < res.length; j++) {
            let item = res[j];
            if (item.to.toLowerCase() == airdropAddress.toLowerCase()) {
                console.log(`${airdropAddress} 自转${item.amount} pizza, txid: ${item.txid}`);
                continue;
            }
            if (!item.valid) {
                console.log(`无效交易txid: ${item.txid}`);
                continue;
            }
            let amount = parseInt(item.amount);
            count += amount;

            let n = dataDir[item.to];
            if (!n) {
                dataDir[item.to] = parseInt(item.amount);
            } else {
                dataDir[item.to] += parseInt(item.amount);
                console.log(`${item.to} 空投多次，txid: ${item.txid}`);
            }


            // let index = data.indexOf(item.to);
            // if (index < 0) {
            //     data.push(item.to);
            //     if (dataStr.length > 0) dataStr += '\n';
            //     dataStr += item.to;
            // } else {
            //     console.log(`${item.to}空投多次，txid: ${item.txid}`);
            // }
        }
    }
    console.log(`共计${Object.keys(dataDir).length}个地址，${count} pizza`);

    /// 写入文件json
    let pizzaAirdropFilePath = path.join(dataDirPath, filename);
    console.log(`开始写入文件, 文件路径: ${pizzaAirdropFilePath}`);
    dataUtil.writeAccountsToFileSync(pizzaAirdropFilePath, dataDir);
    console.log(`下载pizza空投数据完毕！`);
}

// 统计各挡空投数量
async function sumPizzaAirdop(filename) {
    console.log(`开始统计各档pizza空投地址数........`);
    let pizzaAirdropFilePath = path.join(dataDirPath, filename);
    if (!fs.existsSync(pizzaAirdropFilePath)) {
        console.log(`${filename}文件不存在`);
        return;
    }
    let data = dataUtil.readAccountsFromFileSync(pizzaAirdropFilePath);
    let sumDir = {};
    let keys = Object.keys(data);
    for (let i = 0; i < keys.length; i++) {
        let key = keys[i];
        let count = data[key];
        if (!sumDir[count]) {
            sumDir[count] = count;
        } else {
            sumDir[count] += count;
        }
    }
    let sumKeys = Object.keys(sumDir);
    for (let j = 0; j < sumKeys.length; j++) {
        let key = sumKeys[j];
        let value = sumDir[key];
        console.log(`领取${key} pizza的地址数: ${value / key}, 合计：${value} pizza (${(value / supply * 100).toFixed(2)})%`);
    }
}

const pizza = 'pizza';
const maxHolderLimit = 500;
async function sumPizzaFrozenAddress(filename, isCache, cacheFileName) {
    let pizzaAirdropFilePath = path.join(dataDirPath, filename);
    if (!fs.existsSync(pizzaAirdropFilePath)) {
        console.log(`${filename}文件不存在`);
        return;
    }
    let data = dataUtil.readAccountsFromFileSync(pizzaAirdropFilePath);

    let number = await unisatApi.getBrc20HolderNumber(pizza);
    _sleep(1000);
    console.log(`当前pizza持有者数量：${number}`);
    let sum = {};
    /// 获取空投数据
    let page = Math.ceil(number / maxHolderLimit);
    let cacheDir = {};
    for (let i = 0; i < page; i++) {
        let start = i * maxHolderLimit;
        let end = Math.min(start + maxHolderLimit, number);
        console.log(`开始获取${start}-${end}名的持有者.....`);
        let holders = await unisatApi.getBrc20Holder({ ticker: pizza, start: start, limit: maxHolderLimit });
        console.log(`获取成功，正在分析....`);
        for (let j = 0; j < holders.length; j++) {
            let h = holders[j];
            let hN = parseInt(h.overallBalance);
            if (hN < 100) continue;
            let airdropNumber = data[h.address];
            if (!airdropNumber) continue;
            if (hN == airdropNumber) {
                sum[hN] = !sum[hN] ? hN : sum[hN] + hN;
                if (isCache) {
                    cacheDir[h.address] = hN;
                }
            }
        }
        // 防止unisat api调用频率限制
        await _sleep(500);
    }
    let sumKeys = Object.keys(sum);
    let sumAddressNumber = 0;
    let sumPizza = 0;
    for (let j = 0; j < sumKeys.length; j++) {
        let key = sumKeys[j];
        let value = sum[key];
        let addressNumber = value / key;
        sumAddressNumber += addressNumber;
        sumPizza += value;
        console.log(`空投${key} pizza未移动的地址数: ${addressNumber}, 合计：${value} pizza (${(value / supply * 100).toFixed(2)})%`);
    }
    console.log(`共计: ${sumAddressNumber} 地址, ${sumPizza} pizza(${(sumPizza / supply * 100).toFixed(2)}%)`);

    if (isCache) {
        // 缓存数据
        let pizzaFrozenAirdropFilePath = path.join(dataDirPath, cacheFileName);
        console.log(`开始缓存, 文件路径: ${pizzaFrozenAirdropFilePath}`);
        dataUtil.writeAccountsToFileSync(pizzaFrozenAirdropFilePath, cacheDir);
        console.log(`缓存成功！`);
    }
}

async function _sleep(ms) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(true);
        }, ms)
    });
}


run();